package cn.wolfcode.luowowo.search.impl;

import cn.wolfcode.luowowo.repository.StrategyTemplateRepository;
import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.service.IStrategySearchService;
import cn.wolfcode.luowowo.search.template.StrategyTemplate;
import cn.wolfcode.luowowo.search.vo.StatsResult;
import org.apache.dubbo.config.annotation.Service;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.TermsValuesSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.*;

@Service
public class StrategySearchServiceImpl implements IStrategySearchService {

    @Autowired
    private StrategyTemplateRepository repository;

    @Override
    public void save(StrategyTemplate template) {
        repository.save(template);
    }

    /**
     * 站内搜索通过目的地的名字查询攻略
     *
     * @param destName
     * @return
     */
    public List<StrategyTemplate> listByDestName(String destName) {
        return repository.findByDestName(destName);
    }

    /**
     * 主题推荐的操作
     *
     * @return
     */
    public List<Map<String, Object>> themeCommend() {

        List<Map<String, Object>> list = new ArrayList<>();

        //根据主题做桶聚合
        List<StatsResult> vos = groupCondition("themeId", "themeName", 0);

        for (StatsResult vo : vos) {
            //准备 一个map来装themeName和dests的数据
            Map<String, Object> map = new HashMap<>();
            //themeName主题名称
            String themeName = vo.getName();
            map.put("themeName", themeName);
            Long themeId = vo.getId();

            //根据主题的id查询攻略
            List<StrategyTemplate> sts = repository.findByThemeId(themeId, null).getContent();
            //set集合具有去重的效果
            //1.在调用add方法添加元素时,先判断该元素的hash值和集合中原有元素的hash值,不一样则添加进来.
            //2.如果hash值相同,则内部调用equals方法比较值,不同则放入,相同则不加入.
            Set<StatsResult> dests = new HashSet<>();
            //循环遍历得到目的地的id和name
            for (StrategyTemplate st : sts) {
                Long destId = st.getDestId();
                String destName = st.getDestName();
                dests.add(new StatsResult(destId, destName, null));

            }
            //dests当前主题关联的目的地
            map.put("dests", dests);
            //存入集合中
            list.add(map);
        }
        return list;
    }

    /**
     * @param qo
     * @return
     */
    public Page<StrategyTemplate> query(SearchQueryObject qo) {

        Page<StrategyTemplate> page = null;

        switch (qo.getType()) {
            case SearchQueryObject.CONDITION_UNABROAD:
                //根据省份查询
                page = repository.findByProvinceId(qo.getTypeValue(), qo.getPageable());
                break;
            case SearchQueryObject.CONDITION_ABROAD:
                //根据国家查询
                page = repository.findByCountryId(qo.getTypeValue(), qo.getPageable());
                break;
            case SearchQueryObject.CONDITION_THEME:
                //根据主题查询
                page = repository.findByThemeId(qo.getTypeValue(), qo.getPageable());
                break;
            default:
                page = repository.findAll(qo.getPageable());
        }
        return page;
    }

    @Override
    public List<StatsResult> listCondition(int condition) {
        String id = null;
        String name = null;
        switch (condition) {
            case SearchQueryObject.CONDITION_UNABROAD:
                id = "provinceId";
                name = "provinceName";
                break;
            case SearchQueryObject.CONDITION_ABROAD:
                id = "countryId";
                name = "countryName";
                break;
            case SearchQueryObject.CONDITION_THEME:
                id = "themeId";
                name = "themeName";
                break;
        }
        return groupCondition(id, name, condition);
    }

    private List<StatsResult> groupCondition(String id, String name, int condition) {
        String groupType = "groupType";
        String idField = "id";
        String nameField = "name";

        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withPageable(PageRequest.of(0, 1));

        switch (condition) {
            case SearchQueryObject.CONDITION_UNABROAD:
                //CONDITION_UNABROAD->排除非中国数据
                builder.withQuery(QueryBuilders.termQuery("countryId", StatsResult.CHINA_ID));
                break;
            case SearchQueryObject.CONDITION_ABROAD:
                //CONDITION_ABROAD->排除中国数据
                builder.withQuery(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("countryId", StatsResult.CHINA_ID)));
                break;
        }

        //多维度桶聚合条件
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();

        sources.add(new TermsValuesSourceBuilder(idField).field(id));
        sources.add(new TermsValuesSourceBuilder(nameField).field(name));

        CompositeAggregationBuilder group = new CompositeAggregationBuilder(groupType, sources);

        builder.addAggregation(group);
        AggregatedPage<StrategyTemplate> page = (AggregatedPage<StrategyTemplate>) repository.search(builder.build());

        //拿到分组结果
        CompositeAggregation aggs = (CompositeAggregation) page.getAggregation(groupType);

        List<StatsResult> list = new ArrayList<>();
        for (CompositeAggregation.Bucket bucket : aggs.getBuckets()) {
            Map<String, Object> key = bucket.getKey();
            Object idValue = key.get(idField);
            Object nameValue = key.get(nameField);
            long count = bucket.getDocCount();
            list.add(new StatsResult(Long.parseLong(idValue.toString()), nameValue.toString(), count));
        }
        return list;
    }

}
